package com.shycloud.mido.member.service.impl;

import cn.hutool.json.JSONUtil;
import cn.jpush.api.push.PushResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.joy.zebra.common.push.JPushUtils;
import com.shycloud.mido.basic.api.entity.BasDictionary;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.exception.BusinessException;
import com.shycloud.mido.common.security.util.SecurityUtils;
import com.shycloud.mido.homework.api.enums.JPushCodeEnum;
import com.shycloud.mido.member.api.entity.Member;
import com.shycloud.mido.member.api.entity.MsgMemberInfo;
import com.shycloud.mido.member.api.vo.MsgMainVO;
import com.shycloud.mido.member.mapper.MemberMapper;
import com.shycloud.mido.member.mapper.MsgMemberInfoMapper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shycloud.mido.member.api.entity.MsgMain;
import com.shycloud.mido.member.mapper.MsgMainMapper;
import com.shycloud.mido.member.service.MsgMainService;

/**
 * @author nianhua.jiang
 */
@Slf4j
@Service
@AllArgsConstructor
public class MsgMainServiceImpl extends ServiceImpl<MsgMainMapper, MsgMain> implements
		MsgMainService {

	private static final Log logger = LogFactory.getLog(MsgMainServiceImpl.class);


	/** 消息主表 mapper */
	private final MsgMainMapper msgMainMapper;
	/** 用户模块 mapper */
	private final MemberMapper memberMapper;
	/** 消息发送模块 mapper */
	private final MsgMemberInfoMapper memberInfoMapper;

	/** 常量：全体人员推送 */
	private static final String MSG_PUSH_ALL = "0";
	/** 常量：全体教师推送 */
	private static final String MSG_PUSH_TEACHER = "1";
	/** 常量：全体学生推送 */
	private static final String MSG_PUSH_STUDENT = "2";
	/** 常量：人工模式推送 */
	private static final String ARTIFICIAL = "0";
	/** 教师身份 */
	private static final String TEACHER = "1";
	/** 学生身份 */
	private static final String STUDENT = "0";

	/** 常量：推送系统消息类型 */
	private static final String MSG_PUSH_TYPE_SYS = "0";
	/** 常量：推送家校消息类型 */
	private static final String MSG_PUSH_TYPE_DEFAULT = "1";

	@Override
	public IPage<MsgMainVO> getMsg(Page<MsgMainVO> page, String type, String title,
			String startTime, String endTime, String rangeType, Integer orgId, String mode,
			String isApp) {

		//系统消息
		if (MSG_PUSH_TYPE_SYS.equals(type)) {
			return msgMainMapper.getMsg(page, type, title, startTime, endTime, rangeType, orgId, mode);
		}
		//APP端【系统+家校】消息
		else {

			//获取当前用户ID
			String memberId = SecurityUtils.getMember() == null ? null : SecurityUtils.getMember().getId();

			return msgMainMapper.getMsgApp(page, memberId, orgId);
		}
	}

	@Override
	public String addSysMsg(MsgMain msgMain) {

		if (StringUtils.isBlank(msgMain.getTitle())) {
			throw new BusinessException("标题不能为空");
		}

		if (StringUtils.isBlank(msgMain.getMessage())) {
			throw new BusinessException("消息不能为空");
		}

		if (msgMain.getTitle() != null && msgMain.getTitle().length() > 50) {
			throw new BusinessException("标题过长,请重新输入");
		}

		if (msgMain.getMessage() != null && msgMain.getTitle().length() > 1000) {
			throw new BusinessException("内容过长,请重新输入");
		}

		if (MSG_PUSH_TYPE_SYS.equals(msgMain.getType()) && ARTIFICIAL.equals(msgMain.getMode())) {

			//系统消息
			msgMain.setTriggerFrom("0");

			//系统消息
			msgMain.setType(MSG_PUSH_TYPE_SYS);

			if (isOrgPush(msgMain.getOrgId() == null ? 0 : msgMain.getOrgId())) {
				msgMain.setType(MSG_PUSH_TYPE_DEFAULT);
			}

			//0-文本 1-模板 {{可替换}}
			msgMain.setTemplate("0");
			//发送时间
			msgMain.setActualPubDatetime(LocalDateTime.now());
			//0文本 1周报 2IM 3其他
			msgMain.setMsgType("0");
			//创建时间
			msgMain.setCreateTime(LocalDateTime.now());
			//有效数据
			msgMain.setDelFlag("0");
			//模式 0-人工 1-自动
			msgMain.setMode("0");
			//0可以修改 1不可修改
			msgMain.setModify("1");
			//发布时间
			msgMain.setPubDatetime(LocalDateTime.now());
			//0-消息 1-周报 2-作业完成 3-教师认证 4-作业下发
			msgMain.setPoint("0");
			//机构ID
			msgMain.setOrgId(msgMain.getOrgId());

			logger.info("执行推送 =======================>");

			//推送时间
			msgMain.setPushTime(LocalDateTime.now());
			//推送结果
			PushResult pushResult = null;
			List<String> memberIds = new ArrayList<>();
			//全体推送
			if (MSG_PUSH_ALL.equals(msgMain.getRangeType())) {
				pushResult = pushAll(msgMain);
			}
			//全体教师推送
			if (MSG_PUSH_TEACHER.equals(msgMain.getRangeType())) {
				Map<String, Object> reqMap = pushTeaOrStu(msgMain, MSG_PUSH_TEACHER, TEACHER);
				pushResult = (PushResult) reqMap.get("pushResult");
				memberIds = (List<String>) reqMap.get("memberIds");
			}
			//全体学生
			if (MSG_PUSH_STUDENT.equals(msgMain.getRangeType())) {
				Map<String, Object> reqMap = pushTeaOrStu(msgMain, MSG_PUSH_STUDENT, STUDENT);
				pushResult = (PushResult) reqMap.get("pushResult");
				memberIds = (List<String>) reqMap.get("memberIds");
			}

			if (pushResult == null) {
				throw new BusinessException("教师范围未选择");
			}

			//记录推送结果
			if (pushResult.statusCode == 0) {
				//推送状态
				msgMain.setPushStatus(String.valueOf(pushResult.statusCode));
				//错误码
				msgMain.setPushRespCode(String.valueOf(HttpStatus.OK.value()));
				//错误信息
				msgMain.setPushRespMsg(HttpStatus.OK.getReasonPhrase());
			} else {
				msgMain.setPushStatus(String.valueOf(pushResult.statusCode));
				//错误码
				msgMain.setPushRespCode(String.valueOf(pushResult.error.getCode()));
				//错误信息
				msgMain.setPushRespMsg(pushResult.error.getMessage());
			}

			msgMainMapper.insert(msgMain);

			//发送消息
			if (MSG_PUSH_TEACHER.equals(msgMain.getRangeType()) || MSG_PUSH_STUDENT.equals(msgMain.getRangeType())) {

				for (String memberId : memberIds) {
					// 发送消息
					MsgMemberInfo msgMemberInfo = new MsgMemberInfo();
					msgMemberInfo.setMsgId(msgMain.getId());
					msgMemberInfo.setFromId("sys");
					msgMemberInfo.setToId(memberId);
					msgMemberInfo.setDelFlag(CommonConstants.STATUS_NORMAL);
					msgMemberInfo.setCreateTime(LocalDateTime.now());
					memberInfoMapper.insert(msgMemberInfo);
				}

			}

		} else {
			msgMainMapper.insert(msgMain);
		}

		return msgMain.getId();
	}

	@Override
	public List<BasDictionary> getDefaultMsg() {
		return msgMainMapper.getDefaultMsg("default_msg");
	}

	/**
	 * 推送给教师或者学生信息
	 *
	 * @param msgMain   推送信息
	 * @param triggerTo 发送给：1-教师 2-学生 （记录信息用）
	 * @param isTeacher 发送给：0-学生 1-教师 （筛选用户用）
	 * @return cn.jpush.api.push.PushResult
	 * @author nianhua.jiang
	 * @date 2021/6/12 17:49
	 */
	private Map<String, Object> pushTeaOrStu(MsgMain msgMain, String triggerTo, String isTeacher) {

		// 推送身份(1-教师 2-学生)
		msgMain.setTriggerTo(triggerTo);
		// 筛选推送人员
		QueryWrapper<Member> teaClientIdsQw = new QueryWrapper<>();
		//只搜索 client_id 和 id ,避免 * 影响查询效果
		teaClientIdsQw.select("client_id");
		teaClientIdsQw.select("id");

		//============= where 条件 START===================================//
		teaClientIdsQw.eq("is_teacher", isTeacher);
		// 机构只能给对应机构下的 老师/学生 进行推送
		if (isOrgPush(msgMain.getOrgId())) {
			teaClientIdsQw.eq("org_id", msgMain.getOrgId());
		}
		teaClientIdsQw.isNotNull("client_id").ne("client_id", "");
		//============= where 条件 E-N-D===================================//

		List<Member> members = memberMapper.selectList(teaClientIdsQw);
		// 获取推送人员的 regId 集合，用于批量推送
		List<String> teaClientIds = members.stream().map(Member::getClientId).collect(Collectors.toList());
		//获取推送人员的 memberId 集合,用于存储消息详情
		List<String> memberIds = members.stream().map(Member::getId).collect(Collectors.toList());

		//============= 实行分批推送 START ================================//
		//定义每次推送的数量
		int batchSize = 999;
		PushResult pushResult = new PushResult();
		pushResult.statusCode = 0;
		//筛选推送人员 memberId
		if (CollectionUtils.isNotEmpty(teaClientIds)) {
			for (int i = 0; i < teaClientIds.size(); i += batchSize) {
				List<String> ids = teaClientIds.stream().skip(i).limit(batchSize).collect(Collectors.toList());
				if (CollectionUtils.isNotEmpty(ids)) {
					//推送消息
					PushResult pushResultTemp = JPushUtils.sendJPush(msgMain.getTitle(), msgMain.getMessage(), teaClientIds);
					if (0 != pushResultTemp.statusCode) {
						log.error("教师学生批量推送,极光返回错误消息: {} " + JSONUtil.toJsonPrettyStr(pushResultTemp));
						if (pushResult.statusCode == 0) {
							pushResult = pushResultTemp;
						}
					}
					JPushUtils.sendJMessage(JPushCodeEnum.J_PUSH_APP_HOMEPAGE_VIEW.getType(), teaClientIds, "通知APP请求getMsgApp接口");
				}
			}
		}
		//============= 实行分批推送 E-N-D ================================//
		Map<String, Object> resMap = new HashMap<>(2);
		resMap.put("memberIds", memberIds);
		resMap.put("pushResult", pushResult);
		return resMap;
	}

	/**
	 * 全体人员推送
	 *
	 * @param msgMain 推送体
	 * @return void
	 * @author nianhua.jiang
	 * @date 2021/6/12 15:55
	 */
	private PushResult pushAll(MsgMain msgMain) {

		//推送全体人员
		msgMain.setTriggerTo(MSG_PUSH_ALL);
		QueryWrapper<Member> allClientIdsQw = new QueryWrapper<>();
		allClientIdsQw.select("client_id");

		//机构推送只能推送下属成员
		if (isOrgPush(msgMain.getOrgId())) {
			allClientIdsQw.eq("org_id", msgMain.getOrgId());
		}

		allClientIdsQw.isNotNull("client_id").ne("client_id", "");

		List<Object> clientIds = memberMapper.selectObjs(allClientIdsQw);
		//筛选推送人员
		List<String> allClientIds = clientIds.stream().map(String::valueOf).collect(Collectors.toList());
		int batchSize = 999;

		PushResult pushResult = new PushResult();
		pushResult.statusCode = 0;

		//筛选推送人员 memberId
		if (CollectionUtils.isNotEmpty(allClientIds)) {
			for (int i = 0; i < allClientIds.size(); i += batchSize) {
				List<String> ids = allClientIds.stream().skip(i).limit(batchSize).collect(Collectors.toList());
				if (CollectionUtils.isNotEmpty(ids)) {
					//推送消息
					PushResult pushResultTemp = JPushUtils.sendJPush(msgMain.getTitle(), msgMain.getMessage(), allClientIds);
					if (0 != pushResultTemp.statusCode) {
						log.error("批量推送,极光返回错误消息: {} " + JSONUtil.toJsonPrettyStr(pushResultTemp));
						if (pushResult.statusCode == 0) {
							pushResult = pushResultTemp;
						}
					}
					JPushUtils.sendJMessage(JPushCodeEnum.J_PUSH_APP_HOMEPAGE_VIEW.getType(), allClientIds, "通知APP请求getMsgApp接口");
				}
			}
		}
		return pushResult;
	}

	/**
	 * 是否为机构推送
	 *
	 * @param orgId 机构ID
	 * @return boolean
	 * @author nianhua.jiang
	 * @date 2021/6/12 15:52
	 */
	private boolean isOrgPush(Integer orgId) {
		return orgId != 0;
	}

}
